/******************************************
 * Nombre del archivo: Funcion.java
 * Universidad del Valle de Guatemala
 * Curso: Algoritmos y Estructura de Datos
 * Autores:
 *      * Martín Guzmán     08041
 *      * David Hsieh       08225
 *      * Eduardo Mejicano  08058
 *      * Kevin Sánchez     08302
 * Fecha: 16 de agosto de 2009
 * Descripción:
*******************************************/
//(defun promedio (v w x y z) (/ (+ v w x y z) 5))
import java.util.LinkedList;
import java.util.ArrayList;

public class Funcion {

    private static LinkedList<At_Funcion> funciones = new LinkedList<At_Funcion>();

    
    public Funcion(String cadena_funcion){
        //System.out.println("intenta ser función: "+cadena_funcion);

        //para que inicialice algunas funciones de una vez
        if(cadena_funcion.compareTo("")==0){
            funciones.add(new At_Funcion("1+",new At_Lista_Literal("(A)"),"+,A,1,"));
            funciones.add(new At_Funcion("1-",new At_Lista_Literal("(A)"),"-,A,1,"));
        }


        //la sintaxis de la función es correcta.. procede a ingresarla
        else if(Verificar(cadena_funcion)==true){
            //System.out.println("correcta sintaxis función");//TODO quitar esto//Debuguear
            ArrayList<String> listas = Arreglar_texto(cadena_funcion.substring(2,cadena_funcion.length()-1));
            //System.out.println(listas.get(1)+" "+listas.get(2)+" "+listas.get(3).substring(2,listas.get(3).length()-1)); //Debugear
            funciones.add(new At_Funcion(listas.get(1),new At_Lista_Literal(listas.get(2)),listas.get(3).substring(2,listas.get(3).length()-1)));
            
            System.out.println(funciones.getLast().getNombre());//imprime el nombre de la última función
            //System.out.println(funciones.getLast().getLista_funcion_str());//TODO quitar esto
        }
        //sintaxis incorrecta de la función
        else{
            System.out.println("An error has ocurred. Funtion sintaxis is not correct");
        }
    }


    public boolean Verificar(String cadena_funcion){
        if(cadena_funcion.startsWith("(") && cadena_funcion.endsWith(")")){
            ArrayList<String> listas = Arreglar_texto(cadena_funcion.substring(2,cadena_funcion.length()-1));
            //TODO quitar esto //debugear
            /*
            for(int i=0;i<listas.size();i++){
                System.out.println("."+listas.get(i)+".");
            }*/
            //tiene que empezar con la palabra DEFUN
            if(listas.get(0).compareToIgnoreCase("DEFUN")!=0){
                System.out.println("In a funtion the first element has to be the world DEFUN");
                return false;
            }
            //significaría que ya existe una función con ese nombre
            if(Buscar(listas.get(1))==true){
                System.out.println("Sorry. The funtion "+listas.get(1)+" already exist");
                return false;
            }
            if(listas.get(2).startsWith("(")==false && listas.get(2).endsWith(")")==false){
                System.out.println("Sorry. You have to define the parameters of the funtion");
                return false;
            }

            if(listas.get(3).startsWith("(")==false && listas.get(3).endsWith(")")==false){
                System.out.println("Sorry. You have to define a list to operate after the parameters");
                return false;
            }
            else
            {
                //revisar ahora si todo lo que está dentro de la lista que prosigue está
                //definido entre los parámetros
                At_Lista_Literal temporal_literal = new At_Lista_Literal(listas.get(2));
                ArrayList<String> lista_temporal_1 = temporal_literal.lista;

                String texto1 = listas.get(3);
                
                if(texto1.contains("CDR")==false && texto1.contains("CAR")==false && texto1.contains("LIST")==false && texto1.contains(listas.get(1))==false){
                
                    //System.out.println(lista_temporal_1.size());//TODO quitar esto
                    //System.out.println(texto1);
                    for(int i=0;i<lista_temporal_1.size();i++){
                        texto1=texto1.replaceAll(","+lista_temporal_1.get(i),","+(int)(Math.random()*10));//para probar
                    }
                    //System.out.println(texto1);

                    At_Lista lista_de_prueba= new At_Lista(texto1.substring(2,texto1.length()-1));

                    //no evaluar si hay un ciclo...
                    if(lista_de_prueba.texto_lista.contains(listas.get(1)+"")==false && (lista_de_prueba.texto_lista.contains("CDR")==false ) && (lista_de_prueba.texto_lista.contains("CAR")==false ) && (lista_de_prueba.texto_lista.contains("LIST")==false )){
                        //System.out.println(texto1);//TODO quitar esto //debuguear
                        try{
                            //evalúa la expresión y si eso se encuentra incorrecto
                            int prueba = Integer.parseInt(lista_de_prueba.Obtener_valor());
                            //System.out.println(prueba);//TODO quitar esto //debuguear
                        }
                        catch(Exception exp){
                            System.out.println("Sorry the operation in the funtion is not correct");
                            return false;
                        }
                    }
                }
                
            }
            return true;
        }
        return false;
    }

    /*****************************************
     * Método: Arreglar_texto
     * Autor: Martín Guzmán
     * Uso: divide en átomos el texto
     * Retorno: guarda los átomos en una lista.
     *****************************************/
    public ArrayList<String> Arreglar_texto(String texto_lista){
        String[] temporal=texto_lista.split(",");

        //pasar a una lista el arreglo de strings
        ArrayList<String> temporal_lista = new ArrayList<String>();
        for(int i=0;i<temporal.length;i++)
        {
            temporal_lista.add(temporal[i]);
        }
        //***********************************
        ArrayList<String> temporal_a_agregar = new ArrayList<String>();
        for(int i=0;i<temporal_lista.size();i++)
        {
            String sub_cadena=temporal_lista.get(i);
            if (temporal_lista.get(i).startsWith("("))//agrupar hasta que se cierre este paréntesis
            {
                int parentesis=1;
                int posicion=i;
                for(int j=i+1;j<temporal_lista.size();j++){
                    if(temporal[j].contains(")"))
                        parentesis--;
                    if (parentesis==0){
                        posicion=j;
                        break;
                    }
                    if(temporal[j].startsWith("("))
                        parentesis++;

                }
                sub_cadena="";
                //System.out.println("i"+i+" j:"+posicion);//TODO quitar esto
                for(int a=i;a<=posicion;a++){
                   sub_cadena+=","+temporal_lista.get(a);
                }
                sub_cadena=sub_cadena.substring(1, sub_cadena.length());//para quitarle la última ","
                i=posicion;
            }
            //System.out.println("Sub-cadena: ."+sub_cadena+".");//TODO quitar esto
            temporal_a_agregar.add(sub_cadena);
        }
        return temporal_a_agregar;
    }

    /*****************************************
     * Método: Buscar
     * Autor: Martín Guzmán
     * Uso: busca entre las funciones
     * Retorno: booleano para ver si está el nombre
     *          de la función que se está buscando.
     *****************************************/
    public static boolean Buscar(String comp){
        //System.out.println("Buscando dentro de la función a: "+comp);//TODO quitar esto //debuguear
        for(int i=0;i<getFunciones().size();i++){
            if(comp.compareToIgnoreCase(getFunciones().get(i).getNombre())==0){
                return true;
            }
        }
        return false;
    }

    /*****************************************
     * Método: Buscar_Indice
     * Autor: Martín Guzmán
     * Uso: busca entre las funciones.
     * Retorno: entero con el índice en el que
     *          se encuentra determinada función.
     *          -1 si no se encuentra.
     *****************************************/
    public static int Buscar_Indice(String comp){
        //System.out.println("Buscando dentro de la función a: "+comp);//TODO quitar esto //debuguear
        for(int i=0;i<getFunciones().size();i++){
            if(comp.compareToIgnoreCase(getFunciones().get(i).getNombre())==0){
                return i;
            }
        }
        return -1;
    }

    public static LinkedList<At_Funcion> getFunciones() {
        return funciones;
    }


}
